const defaultConfig = require('./default-config.json');
const genPins = require('./gen-pins');
var seneca;

function getDefaultDiscoveryEndPoints() {
    return [
        {
            id: 'discovery-default',
            senecaOpt: {
                "type": "http",
                host: '127.0.0.1',
                port: '10851',
                pin: 'role: registration, cmd: *'
            }
        }
    ];
}

async function setup(options = { dontEnroll: false, permissions: defaultConfig.permissions }) {
    let { permissions } = options;
    if(!permissions) {
        options.permissions = defaultConfig.permissions;
        permissions = defaultConfig.permissions;
    }
    if (!options.dontEnroll) {
        await enrollToRegistration(options);
        return;
    }
    seneca = require('seneca')()
        .use('balance-client')
        .client({ type: 'balance', pins: permissions })
}

function act(...args) {
    assertInvoke(...args);
    seneca.act(...args);
    return this;
}

async function actAsync(...args) {
    assertInvoke(...args);
    return new Promise((resolve, reject) => {
        seneca.act(...args, (error, result) => {
            if (error) {
                reject(error);
                return;
            }
            resolve(result);
        });
    });
}

function assertInvoke() {
    if (!seneca) {
        throw new Error('should invoke setup before got seneca invoker!');
    }
}

function enrollToRegistration(options) {
    return new Promise((resolve, reject) => {
        let discovery = require('seneca')();
        let discoveryEndPoint = options.discoveryEndPoints || getDefaultDiscoveryEndPoints();
        discoveryEndPoint.forEach(endPoint => {
            let { type, host, port, pin } = endPoint.senecaOpt;
            let pins = genPins(pin);
            discovery.client({ type, host, port, pins });
        });

        discovery.act('role: registration, cmd:list', (err, endPoints) => {
            if (err) {
                reject(err);
                return;
            }
            console.log(`endpoints found...${JSON.stringify(endPoints)}`);
            let initSeneca = require('seneca')()
                .use('balance-client')
                .client({ type: 'balance', pins: options.permissions });
            endPoints.forEach(endPoint => {
                let { type, host, port, pin, pins } = endPoint.senecaOpt;
                initSeneca.client({ type, host, port, pin, pins });
            });
            seneca = initSeneca;
            resolve(this);
        });
    });
}

module.exports = {
    setup,
    get seneca() {
        assertInvoke();
        return seneca;
    },
    act,
    actAsync
};